const { exec } = require('child_process')
const fse = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const ora = require('ora')

const { SupportedLanguage, SupportedFramework, SupportedStyleSheets } = require('./consts')

// 需要安装的npm模块
const CommonDeps = [
	['@commitlint/cli', '^19.8.1'],
	['@commitlint/config-conventional', '^19.8.1'],
	['@commitlint/prompt-cli', '^20.1.0'],
	['cz-conventional-changelog', '^3.3.0'],
	['husky', '^9.1.7'],
	['lint-staged', '^16.1.2'],
	['prettier', '^3.6.2']
]

const HtmlDeps = [['stylelint-config-html', '^1.1.0']]

const EsLintDeps = [
	['eslint', '^9.39.1'],
	['eslint-config-prettier', '^9.1.2'],
	['eslint-plugin-prettier', '^5.5.4'],
	['@babel/eslint-parser', '^7.12.16'],
	['@babel/preset-env', '^7.28.5']
]

const TypeScriptDeps = [
	['@typescript-eslint/eslint-plugin', '^8.46.3'],
	['@typescript-eslint/parser', '^8.46.3']
]

const StyleDeps = [
	['stylelint', '^15.10.3'],
	['stylelint-config-recess-order', '^7.4.0'],
	['stylelint-config-standard', '^34.0.0'],
	['stylelint-order', '^6.0.4']
]

const ScssDeps = [
	['postcss-scss', '^4.0.9'],
	['stylelint-config-recommended-scss', '^12.0.0'],
	['stylelint-scss', '^5.3.2']
]

const LessDeps = [
	['postcss-less', '^6.0.0'],
	['stylelint-config-recommended-less', '^2.0.0'],
	['stylelint-less', '^1.0.6']
]

const Vue2Deps = [
	['postcss-html', '^1.8.0'],
	['eslint-plugin-vue', '^9.33.0'],
	['stylelint-config-html', '^1.1.0'],
	['vue-eslint-parser', '^9.4.3']
]

const Vue3Deps = [
	['postcss-html', '^1.8.0'],
	['stylelint-config-html', '^1.1.0'],
	['eslint-plugin-vue', '^9.33.0'],
	['vue-eslint-parser', '^9.4.3']
]

const ReactDeps = [
	['eslint-plugin-react', '^7.37.5'],
	['eslint-plugin-react-hooks', '^5.2.0']
]

module.exports = {
	apply: ({ language, framework, styleSheets, includeHtml }) => {
		console.log(chalk.blue('安装依赖包...'))
		const deps = CommonDeps.slice()

		// html依赖
		if (includeHtml) {
			deps.push(...HtmlDeps)
		}

		// eslint 相关依赖
		if (language !== SupportedLanguage.others) {
			deps.push(...EsLintDeps)
		}
		// typescript依赖
		if (language === SupportedLanguage.typescript) {
			deps.push(...TypeScriptDeps)
		}

		// 开发框架依赖
		if (framework === SupportedFramework.vue2) {
			deps.push(...Vue2Deps)
		} else if (framework === SupportedFramework.vue3) {
			deps.push(...Vue3Deps)
		} else if (framework === SupportedFramework.react) {
			deps.push(...ReactDeps)
		}

		// 样式处理相关依赖
		if (styleSheets !== SupportedStyleSheets.others) {
			deps.push(...StyleDeps)
			if (styleSheets === SupportedStyleSheets.scss) {
				deps.push(...ScssDeps)
			} else if (styleSheets === SupportedStyleSheets.less) {
				deps.push(...LessDeps)
			}
		}

		const lockFiles = ['pnpm-lock.yaml', 'yarn.lock', 'package-lock.json']
		let installCmd = 'npm i -D'
		for (const lockFile of lockFiles) {
			if (fse.existsSync(path.resolve(process.cwd(), `./${lockFile}`))) {
				if (lockFile === 'pnpm-lock.yaml') {
					installCmd = 'pnpm add -D'
				} else if (lockFile === 'yarn.lock') {
					installCmd = 'yarn add -D'
				}
				break
			}
		}

		const defer = deps.map(([pkgName, version]) => {
			const pkgInfo = `${pkgName}@${version}`
			console.log(chalk.yellow(pkgInfo))

			return new Promise((resolve, reject) => {
				const cmdProcess = exec(installCmd + ' ' + `${pkgInfo} --legacy-peer-deps`, (error, stdout, stderr) => {
					if (error) {
						console.log(chalk.red(error))
						reject(new Error('安装失败: ', error))
					}
				})

				cmdProcess.on('close', code => {
					if (code === 0) {
						resolve(code)
					} else {
						reject(new Error('安装失败: ', code))
					}
				})
			})
		})

		const spinner = ora('>>>>>> 正在安装依赖包 >>>>>>\n').start()
		Promise.allSettled(defer).then(res => {
			if (res.every(item => item.status === 'fulfilled')) {
				spinner.succeed('安装完成')
			} else {
				spinner.fail('安装失败')
			}
			process.exit()
		})
	}
}
